一个自定义的线程类,其也是一个普通的类,不同的使用方式,其实例变量对调用其的线程来说存在共享和不共享的情形。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class CustomThread extends Thread {
private int count = 3;
public CustomThread() {
super();
}
public void run() {
super.run();
while (count > 0) {
System.out.println(this.currentThread().getId() + " 计算,count=" + count);
count--;
}
}
}
不共享的情形
不共享实例变量的情形是创建多个自定义线程类的实例:1
2
3
4
5
6
7
8
9
10
11public class CustomThreadTest {
public static void main(String[] args) {
CustomThread customThreadA = new CustomThread();
CustomThread customThreadB = new CustomThread();
CustomThread customThreadC = new CustomThread();
customThreadA.start();
customThreadB.start();
customThreadC.start();
}
}
结果可能:1
2
3
4
5
6
7
8
911 计算,count=3
11 计算,count=2
11 计算,count=1
12 计算,count=3
12 计算,count=2
12 计算,count=1
13 计算,count=3
13 计算,count=2
13 计算,count=1
结果可能:1
2
3
4
5
6
7
8
911 计算,count=3
13 计算,count=3
12 计算,count=3
13 计算,count=2
12 计算,count=2
13 计算,count=1
12 计算,count=1
11 计算,count=2
11 计算,count=1
虽然由于线程执行顺序的随机性,但是每个线程实例均各自计算各自的实例变量 count
共享的情形
共享实例变量的情形是创建一个自定义线程类的实例,然后多个其他线程实例调用自定义线程类实例(此时自定义线程类相当于一个普通的类):1
2
3
4
5
6
7
8
9
10
11
12public class CustomThreadTest {
public static void main(String[] args) {
CustomThread customThread = new CustomThread();
Thread threadA = new Thread(customThread);
Thread threadB = new Thread(customThread);
Thread threadC = new Thread(customThread);
threadA.start();
threadB.start();
threadC.start();
}
}
结果可能:1
2
3
412 计算,count=3
13 计算,count=3
12 计算,count=2
13 计算,count=1
结果可能:1
2
3
4
512 计算,count=3
14 计算,count=3
13 计算,count=3
14 计算,count=1
12 计算,count=2
结果可能:1
2
3
4
513 计算,count=3
13 计算,count=2
13 计算,count=1
14 计算,count=3
12 计算,count=-1
虽然由于线程执行顺序的随机性,但是每个线程实例均计算了 CustomThread 实例 customThread 的实例变量 count。
而且上述结果,看起来非常奇怪,与期望的相差甚远!这就是线程安全问题!
以上述例子为例,某些 JVM 中,i– 实际是三步操作:
1)获取原 i 值
2)计算 i-1
3) 对 i 进行赋值
正是因为分步操作,可能在执行完第一步以后,线程执行就会切换,导致执行结果千奇百怪,和期望不符。
若想解决线程安全问题,则需要执行线程同步策略。
synchronized 关键字修改线程内的方法,可以使其即使被多个线程调用,其也是按顺序执行,从而保证线程安全。
使用 synchronized 关键字修饰 run() 方法:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class CustomThread extends Thread {
private int count = 3;
public CustomThread() {
super();
}
public synchronized void run() {
super.run();
while (count > 0) {
System.out.println(this.currentThread().getId() + " 计算,count=" + count);
count--;
}
}
}
结果可能是:1
2
312 计算,count=3
12 计算,count=2
12 计算,count=1
结果可能是:1
2
314 计算,count=3
14 计算,count=2
14 计算,count=1
执行结果只是因为线程执行的随机而不同,但是计算过程是与期望一致的:count 计算三次